1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.systems.hotload;
12 
13 version(Load_DScript):
14 import std.file : copy, rename;
15 import hip.filesystem.hipfs;
16 import hip.util.system;
17 import hip.util.path;
18 import hip.console.log;
19 import hip.error.handler;
20 
21 class HotloadableDLL
22 {
23     void* lib;
24 
25     immutable string trueLibPath;
26     void delegate (void* libPointer) onDllLoad;
27     string tempDll;
28     string tempPdb;
29     this(string path, void delegate (void* libPointer) onDllLoad)
30     {
31         ErrorHandler.assertExit(path != null, "DLL path should not be null:
32 Call `dub -c script -- path/to/project` dub -c script requires that argument.");
33 
34         import std.path;
35         path = absolutePath(path).buildNormalizedPath;
36         if(HipFS.absoluteIsDir(path))
37             path = joinPath(path, path.filenameNoExt);
38         if(!dynamicLibraryIsLibNameValid(path))
39             path = dynamicLibraryGetLibName(path);
40         trueLibPath = path;
41         this.onDllLoad = onDllLoad;
42         load(path);
43     }
44     protected bool load(string path)
45     {
46         import std.file;
47         if(!HipFS.absoluteExists(path))
48         {
49             import hip.console.log;
50             logln("Does not exists ", path);
51             return false;
52         }
53         //Create dll_hiptempdll
54         tempDll = getTempName(path);
55         copy(path, tempDll);
56 
57         // version(Windows)
58         // {{
59         //     import std.process:executeShell;
60         //     import hip.util.path;
61         //     string tempDirectory = joinPath(path.dirName, "temp");
62         //     mkdirRecurse(tempDirectory);
63             
64         //     string thePdb = path.extension("pdb");
65         //     tempPdb = getTempName(thePdb);
66         //     if(exists(thePdb))
67         //     {
68         //         copy(thePdb, joinPath(tempDirectory, thePdb.baseName));
69         //         rename(thePdb, tempPdb);
70         //     }
71 
72         // }}
73 
74 
75         loglnInfo("Loading dll ", path);
76         lib = dynamicLibraryLoad(tempDll);
77         if(onDllLoad && lib != null)
78             onDllLoad(lib);
79         else if(lib == null)
80             loglnError("Could not load dll ", path);
81         return lib != null;
82     }
83     /** 
84      * 
85      * Params:
86      *   path = File path
87      * Returns: filePath.(ext)_hiptempdll
88      */
89     static string getTempName(string path)
90     {
91         import hip.util.string;
92         string d = dirName(path);
93         string n = baseName(path);
94         string ext = extension(n);
95         
96         int ind = lastIndexOf(n, "_hiptemp");
97         if(ind != -1)
98             return path;
99         return joinPath(d, n[0..$-(ext.length+1)]~"_hiptemp."~ext);
100     }
101 
102     void reload()
103     {
104         if(lib != null)
105         {
106             dynamicLibraryRelease(lib);
107             lib = null;
108         }
109         load(trueLibPath);
110     }
111 
112     void dispose()
113     {
114         import hip.error.handler;
115         if(lib != null)
116         {
117             if(!dynamicLibraryRelease(lib))
118                 return ErrorHandler.showErrorMessage("Could not unload the dll ", tempDll);
119             
120             foreach(remFile; [tempDll, tempPdb]) 
121             if(remFile && !HipFS.absoluteRemove(remFile))
122             {
123                 ErrorHandler.showErrorMessage("Could not remove ", remFile);
124             }
125         }
126     }
127 }